The moving average function

The moving average averages each observation of a series with its surrounding observations in chronological order. The main components of the MA function are:

The rolling window structure

The most common types of window structures are:

  • The one-sided window: a sliding window with a width of n which groups each observation of the series with its past consecutive n-1 observations.

  • The two-sided window: rolling window which groups each observation with its past \(n_1\) and future \(n_2\) observations.

The average method

  • the arithmetic average: based on summing all observations and dividing them by the number of observations

  • The weighted average: based on applying a weight to each observation of the series

The MA attributes

The MA function has two primary attributes that are derived directly from the window structure.

  • Order: this defines the magnitude of the MA and is equal to the length of the window

  • Cost: the cost is the loss of observations during the transformation of the origin series to the smoothed series by the MA process.

The main applications of the MA function are:

  • Noise reduction: the use of the MA method creates a smoothing effect that reduces series variation, smoothing the random noise and outliers.

  • De-seasonalize: used to remove the seasonal component

  • Forecasting: can be used to forecast

Let’s see an example of a one-sided MA with an arithmetic average, known as a simple MA, a two-sided MA and a weighted MA.

The simple moving average

Let’s build our own simple moving average function. We will do so by creating a rolling window function and an average function.

head(lags(USVSales, l = 3))
          y    y_1    y_2    y_3
[1,] 1092.1  969.9 1061.8 1084.4
[2,] 1451.1 1092.1  969.9 1061.8
[3,] 1354.4 1451.1 1092.1  969.9
[4,] 1377.1 1354.4 1451.1 1092.1
[5,] 1459.8 1377.1 1354.4 1451.1
[6,] 1202.0 1459.8 1377.1 1354.4

Two-sided MA

two_sided_ma <- ts_ma(ts.obj = USVSales,
                      n = c(2, 5),
                      n_left = 6,
                      n_right = 5,
                      plot = TRUE,
                      multiple = TRUE,
                      margin = 0.4)
A line object has been specified, but lines is not in the mode
Adding lines to the mode...
A line object has been specified, but lines is not in the mode
Adding lines to the mode...
A line object has been specified, but lines is not in the mode
Adding lines to the mode...

The higher the order of the function, the smoother the output.

A simple MA versus a two-sided MA

A two-sided MA is more approprate to apply as a smoother or data filter method. A one-sided MA makes sense when you need to have the most recent observations.

The time series components

Patterns in time series analysis can be categorized into one of the following:

We can use these two groups of patterns to express time series data using the following equation when the series has an additive structure:

\[ Y_t = T_t + S_t + C_t + I_t \]

And when the series has a multiplicative structure:

\[ Y_t = T_t \times S_t \times C_t \times I_t \]

The cycle component

ts_info(USUnRate)
 The USUnRate series is a ts object with 1 variable and 864 observations
 Frequency: 12 
 Start time: 1948 1 
 End time: 2019 12 

We don’t need to plot the entire series, so we will subset it with a window function:

The trend component

A trend is a general direction in a series.

The seasonal component

A seasonal trend is one that has repeated variation over time.

The seasonal component versus the cycle component

The plot above shows a seasonal cycle.

This plot shows cycles.

White noise

A white noise pattern is a lack of a pattern. There are some methods to test if a series is white noise.

  • plot it out an eyeball

  • Measure the correlation with the autocorrelation function

  • the Ljung-Box testz; the null hypothesis assumes that the lags are not correlated.

The irregular component

This is the remainder between the series and structural components.

The additive versus the multiplicative model

We classify a series as additive whenever there is growth in the trend, or if the amplitude of the seasonal component remains the same over time.

We classify a series as multiplicative whenever the growth of the trend or the magnitude of the seasonal component increases or decreases by some multiplicity from period to period over time.

Here is an example of an additive series:

Here is an example of a multiplicative series:

Handling multiplicative series

Most forecasting models assume that the variation of the input series remains constant over time. This usually holds for a series with an additive structure, but fails with a multiplicative structure. The common solution is to apply a data transformation:

  • log transformation: apply the \(log\) to both sides of the series equation

  • box-cox transformation: applying power on the input series with the box-cox formula

air_passenger_lambda
[1] -0.2947156

We can use the coefficient to transform the input series with the BoxCox transformation and plot it:

The decomposition of time series

Once the data has been cleaned and reformatted, we need to identify the structure of the series components. The decomposition of a series is a generic name for the process of separating a series into its components.

Classical seasonal decomposition

This is a three step process:

  1. trend estimation: uses the MA function to remove the seasonal component from the series. THe order of the MA function is determined by the frequency of the series.
  2. Seasonal component estimation: Two step process that starts with detrending the series by subtracting the trend estimation from the previous step. After the series is detrended, the next step is to estimate the seasonal component for each frequency unit. This is done by grouping the observations by their frequency unit and then averaging each group.
  3. Irregular component estimation: subtracting the estimation of the trend and seasonal components from the original series.

We can do all of this with the decompose() function:

str(usv_decomposed)
List of 6
 $ x       : Time-Series [1:528] from 1976 to 2020: 885 995 1244 1191 1203 ...
 $ seasonal: Time-Series [1:528] from 1976 to 2020: -225.2 -102.4 143 34.5 147.9 ...
 $ trend   : Time-Series [1:528] from 1976 to 2020: NA NA NA NA NA ...
 $ random  : Time-Series [1:528] from 1976 to 2020: NA NA NA NA NA ...
 $ figure  : num [1:12] -225.2 -102.4 143 34.5 147.9 ...
 $ type    : chr "additive"
 - attr(*, "class")= chr "decomposed.ts"
  • x is the original series

  • seasonal is the estimate of the seasonal trend

  • trend is the estimate of the series trend

  • random is the irregular component

  • figure estimated seasonal figure only

  • type the type of decomposition, either additive or multiplicative

And with a multiplicative model:

One limitation of the classical decomposition method is that the seasonal component uses the arithmetic average. This means that there is a single seasonal component estimation for each cycle unit. This is fine with additive models, but can be problematic with multiplicative models since the seasonal aspect changes over time.

Seasonal Adjustment

Seasonal adjustment is the process of removing the seasonal fluctuation from a series. The transformation process of the seasonal adjustment method is straightforward:

  1. Estimate the seasonal component using a decomposition process
  2. Remove the seasonal component from the series, which leaves the series with only the trend and the irregular component
  3. Optionall, you can apply a smoothing function to remove noise and outliers
LS0tCnRpdGxlOiAiQ2hhcHRlciA0OiBEZWNvbXBvc2l0aW9uIG9mIFRpbWUgU2VyaWVzIERhdGEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgVGhlIG1vdmluZyBhdmVyYWdlIGZ1bmN0aW9uCgpUaGUgbW92aW5nIGF2ZXJhZ2UgYXZlcmFnZXMgZWFjaCBvYnNlcnZhdGlvbiBvZiBhIHNlcmllcyB3aXRoIGl0cyBzdXJyb3VuZGluZyBvYnNlcnZhdGlvbnMgaW4gY2hyb25vbG9naWNhbCBvcmRlci4gVGhlIG1haW4gY29tcG9uZW50cyBvZiB0aGUgTUEgZnVuY3Rpb24gYXJlOgoKLSAgIFRoZSByb2xsaW5nIHdpbmRvdzogQSBnZW5lcmljIGZ1bmN0aW9uIHRoYXQgc2xpZGVzIGFsb25nIGRhdGEgaW4gY2hyb25vbG9naWNhbCBvcmRlcgoKLSAgIEF2ZXJhZ2UgZnVuY3Rpb246IHRoaXMgaXMgZWl0aGVyIGEgc2ltcGxlIG9yIHdlaWdodGVkIGF2ZXJhZ2UKCiMjIFRoZSByb2xsaW5nIHdpbmRvdyBzdHJ1Y3R1cmUKClRoZSBtb3N0IGNvbW1vbiB0eXBlcyBvZiB3aW5kb3cgc3RydWN0dXJlcyBhcmU6CgotICAgVGhlIG9uZS1zaWRlZCB3aW5kb3c6IGEgc2xpZGluZyB3aW5kb3cgd2l0aCBhIHdpZHRoIG9mICpuKiB3aGljaCBncm91cHMgZWFjaCBvYnNlcnZhdGlvbiBvZiB0aGUgc2VyaWVzIHdpdGggaXRzIHBhc3QgY29uc2VjdXRpdmUgKm4tMSogb2JzZXJ2YXRpb25zLgoKLSAgIFRoZSB0d28tc2lkZWQgd2luZG93OiByb2xsaW5nIHdpbmRvdyB3aGljaCBncm91cHMgZWFjaCBvYnNlcnZhdGlvbiB3aXRoIGl0cyBwYXN0ICRuXzEkIGFuZCBmdXR1cmUgJG5fMiQgb2JzZXJ2YXRpb25zLgoKIyMgVGhlIGF2ZXJhZ2UgbWV0aG9kCgotICAgdGhlIGFyaXRobWV0aWMgYXZlcmFnZTogYmFzZWQgb24gc3VtbWluZyBhbGwgb2JzZXJ2YXRpb25zIGFuZCBkaXZpZGluZyB0aGVtIGJ5IHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zCgotICAgVGhlIHdlaWdodGVkIGF2ZXJhZ2U6IGJhc2VkIG9uIGFwcGx5aW5nIGEgd2VpZ2h0IHRvIGVhY2ggb2JzZXJ2YXRpb24gb2YgdGhlIHNlcmllcwoKIyMgVGhlIE1BIGF0dHJpYnV0ZXMKClRoZSBNQSBmdW5jdGlvbiBoYXMgdHdvIHByaW1hcnkgYXR0cmlidXRlcyB0aGF0IGFyZSBkZXJpdmVkIGRpcmVjdGx5IGZyb20gdGhlIHdpbmRvdyBzdHJ1Y3R1cmUuCgotICAgT3JkZXI6IHRoaXMgZGVmaW5lcyB0aGUgbWFnbml0dWRlIG9mIHRoZSBNQSBhbmQgaXMgZXF1YWwgdG8gdGhlIGxlbmd0aCBvZiB0aGUgd2luZG93CgotICAgQ29zdDogdGhlIGNvc3QgaXMgdGhlIGxvc3Mgb2Ygb2JzZXJ2YXRpb25zIGR1cmluZyB0aGUgdHJhbnNmb3JtYXRpb24gb2YgdGhlIG9yaWdpbiBzZXJpZXMgdG8gdGhlIHNtb290aGVkIHNlcmllcyBieSB0aGUgTUEgcHJvY2Vzcy4KClRoZSBtYWluIGFwcGxpY2F0aW9ucyBvZiB0aGUgTUEgZnVuY3Rpb24gYXJlOgoKLSAgIE5vaXNlIHJlZHVjdGlvbjogdGhlIHVzZSBvZiB0aGUgTUEgbWV0aG9kIGNyZWF0ZXMgYSBzbW9vdGhpbmcgZWZmZWN0IHRoYXQgcmVkdWNlcyBzZXJpZXMgdmFyaWF0aW9uLCBzbW9vdGhpbmcgdGhlIHJhbmRvbSBub2lzZSBhbmQgb3V0bGllcnMuCgotICAgRGUtc2Vhc29uYWxpemU6IHVzZWQgdG8gcmVtb3ZlIHRoZSBzZWFzb25hbCBjb21wb25lbnQKCi0gICBGb3JlY2FzdGluZzogY2FuIGJlIHVzZWQgdG8gZm9yZWNhc3QKCkxldCdzIHNlZSBhbiBleGFtcGxlIG9mIGEgb25lLXNpZGVkIE1BIHdpdGggYW4gYXJpdGhtZXRpYyBhdmVyYWdlLCBrbm93biBhcyBhIHNpbXBsZSBNQSwgYSB0d28tc2lkZWQgTUEgYW5kIGEgd2VpZ2h0ZWQgTUEuCgpgYGB7cn0KbGlicmFyeShUU3N0dWRpbykKZGF0YSgiVVNWU2FsZXMiKQoKdHNfaW5mbyhVU1ZTYWxlcykKCnRzX3Bsb3QoVVNWU2FsZXMsCiAgICAgICAgdGl0bGUgPSAiVVMgTW9udGhseSBUb3RhbCBWZWhpY2xlIFNhbGVzIiwKICAgICAgICBZZ3JpZCA9IFRSVUUsCiAgICAgICAgWGdyaWQgPSBUUlVFKQpgYGAKCiMjIFRoZSBzaW1wbGUgbW92aW5nIGF2ZXJhZ2UKCkxldCdzIGJ1aWxkIG91ciBvd24gc2ltcGxlIG1vdmluZyBhdmVyYWdlIGZ1bmN0aW9uLiBXZSB3aWxsIGRvIHNvIGJ5IGNyZWF0aW5nIGEgcm9sbGluZyB3aW5kb3cgZnVuY3Rpb24gYW5kIGFuIGF2ZXJhZ2UgZnVuY3Rpb24uCgpgYGB7cn0KbGFncyA8LSBmdW5jdGlvbih0cy5vYmosIGwpIHsKICB0c19tZXJnZWQgPC0gTlVMTAogIAogICMgY3JlYXRpbmcgbiBsYWdzCiAgZm9yIChpIGluIDE6bCkgewogICAgdHNfbWVyZ2VkIDwtIHRzLnVuaW9uKHRzX21lcmdlZCwgc3RhdHM6OmxhZyh0cy5vYmosIGsgPSAtaSkpCiAgfQogIAogICMgbWVyZ2UgdGhlIGxhZ3Mgd2l0aCB0aGUgb3JpZ2luYWwgc2VyaWVzCiAgdHNfbWVyZ2VkIDwtIHRzLnVuaW9uKHRzLm9iaiwgdHNfbWVyZ2VkKQogIAogICMgc2V0IHRoZSBjb2x1bW4gbmFtZXMKICBjb2xuYW1lcyh0c19tZXJnZWQpIDwtIGMoInkiLCBwYXN0ZTAoInlfIiwgMTppKSkKICAKICAjIHJlbW92aW5nIG1pc3NpbmcgdmFsdWVzIGFzIHJlc3VsdHMgb2YgY3JlYXRpbmcgdGhlIGxhZ3MKICB0c19tZXJnZWQgPC0gd2luZG93KHRzX21lcmdlZCwgCiAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IHN0YXJ0KHRzLm9iaikgKyAxLAogICAgICAgICAgICAgICAgICAgICAgZW5kID0gZW5kKHRzLm9iaikpCiAgCiAgcmV0dXJuKHRzX21lcmdlZCkKfQoKaGVhZChsYWdzKFVTVlNhbGVzLCBsID0gMykpCmBgYAoKIyMgVHdvLXNpZGVkIE1BCgpgYGB7cn0KdHdvX3NpZGVkX21hIDwtIHRzX21hKHRzLm9iaiA9IFVTVlNhbGVzLAogICAgICAgICAgICAgICAgICAgICAgbiA9IGMoMiwgNSksCiAgICAgICAgICAgICAgICAgICAgICBuX2xlZnQgPSA2LAogICAgICAgICAgICAgICAgICAgICAgbl9yaWdodCA9IDUsCiAgICAgICAgICAgICAgICAgICAgICBwbG90ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG11bHRpcGxlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1hcmdpbiA9IDAuNCkKYGBgCgpUaGUgaGlnaGVyIHRoZSBvcmRlciBvZiB0aGUgZnVuY3Rpb24sIHRoZSBzbW9vdGhlciB0aGUgb3V0cHV0LgoKIyMgQSBzaW1wbGUgTUEgdmVyc3VzIGEgdHdvLXNpZGVkIE1BCgpgYGB7cn0Kb25lX3NpZGVkXzEyIDwtIHRzX21hKFVTVlNhbGVzLCBuID0gTlVMTCwgbl9sZWZ0ID0gMTEsIHBsb3QgPSBGQUxTRSkKdHdvX3NpZGVkXzEyIDwtIHRzX21hKFVTVlNhbGVzLCBuID0gTlVMTCwgbl9sZWZ0ID0gNiwgbl9yaWdodCA9IDUsIHBsb3QgPSBGQUxTRSkKb25lX3NpZGVkIDwtIG9uZV9zaWRlZF8xMiR1bmJhbGFuY2VkX21hXzEyCnR3b19zaWRlZCA8LSB0d29fc2lkZWRfMTIkdW5iYWxhbmNlZF9tYV8xMgoKbWEgPC0gY2JpbmQoVVNWU2FsZXMsIG9uZV9zaWRlZCwgdHdvX3NpZGVkKQoKdHNfcGxvdChtYSkKYGBgCgpBIHR3by1zaWRlZCBNQSBpcyBtb3JlIGFwcHJvcHJhdGUgdG8gYXBwbHkgYXMgYSBzbW9vdGhlciBvciBkYXRhIGZpbHRlciBtZXRob2QuIEEgb25lLXNpZGVkIE1BIG1ha2VzIHNlbnNlIHdoZW4geW91IG5lZWQgdG8gaGF2ZSB0aGUgbW9zdCByZWNlbnQgb2JzZXJ2YXRpb25zLgoKIyBUaGUgdGltZSBzZXJpZXMgY29tcG9uZW50cwoKUGF0dGVybnMgaW4gdGltZSBzZXJpZXMgYW5hbHlzaXMgY2FuIGJlIGNhdGVnb3JpemVkIGludG8gb25lIG9mIHRoZSBmb2xsb3dpbmc6CgotICAgU3RydWN0dXJhbCBQYXR0ZXJuczogYWxzbyBrbm93biBhcyBzZXJpZXMgY29tcG9uZW50cy4gVGhlcmUgYXJlIHRocmVlIHR5cGVzIC0gdHJlbmQsIGN5Y2xlLCBhbmQgc2Vhc29uYWwuCgotICAgTm9uLXN0cnVjdHVyYWw6IGFsc28ga25vd24gYXMgdGhlIGlycmVndWxhciBjb21wb25lbnQgYW5kIHJlZmVycyB0byBhbnkgb3RoZXIgdHlwZXMgb2YgcGF0dGVybnMgaW4gdGhlIGRhdGEuCgpXZSBjYW4gdXNlIHRoZXNlIHR3byBncm91cHMgb2YgcGF0dGVybnMgdG8gZXhwcmVzcyB0aW1lIHNlcmllcyBkYXRhIHVzaW5nIHRoZSBmb2xsb3dpbmcgZXF1YXRpb24gd2hlbiB0aGUgc2VyaWVzIGhhcyBhbiBhZGRpdGl2ZSBzdHJ1Y3R1cmU6CgokJApZX3QgPSBUX3QgKyBTX3QgKyBDX3QgKyBJX3QKJCQKCkFuZCB3aGVuIHRoZSBzZXJpZXMgaGFzIGEgbXVsdGlwbGljYXRpdmUgc3RydWN0dXJlOgoKJCQKWV90ID0gVF90IFx0aW1lcyBTX3QgXHRpbWVzIENfdCBcdGltZXMgSV90CiQkCgojIyBUaGUgY3ljbGUgY29tcG9uZW50CgpgYGB7cn0KZGF0YSgiVVNVblJhdGUiKQoKdHNfaW5mbyhVU1VuUmF0ZSkKYGBgCgpXZSBkb24ndCBuZWVkIHRvIHBsb3QgdGhlIGVudGlyZSBzZXJpZXMsIHNvIHdlIHdpbGwgc3Vic2V0IGl0IHdpdGggYSBgd2luZG93YCBmdW5jdGlvbjoKCmBgYHtyfQp1bmVtcGxveW1lbnQgPC0gd2luZG93KFVTVW5SYXRlLCBzdGFydCA9IGMoMTk5MCwgMSkpCgp0c19wbG90KHVuZW1wbG95bWVudCkKYGBgCgojIyBUaGUgdHJlbmQgY29tcG9uZW50CgpBIHRyZW5kIGlzIGEgZ2VuZXJhbCBkaXJlY3Rpb24gaW4gYSBzZXJpZXMuCgpgYGB7cn0Kc2V0LnNlZWQoMTIzNCkKCnRzX25vbl90cmVuZCA8LSB0cyhydW5pZigyMDAsIDUsIDUuMiksCiAgICAgICAgICAgICAgICAgICBzdGFydCA9IGMoMjAwMCwgMSksCiAgICAgICAgICAgICAgICAgICBmcmVxdWVuY3kgPSAxMikKYGBgCgojIyBUaGUgc2Vhc29uYWwgY29tcG9uZW50CgpBIHNlYXNvbmFsIHRyZW5kIGlzIG9uZSB0aGF0IGhhcyByZXBlYXRlZCB2YXJpYXRpb24gb3ZlciB0aW1lLgoKIyMgVGhlIHNlYXNvbmFsIGNvbXBvbmVudCB2ZXJzdXMgdGhlIGN5Y2xlIGNvbXBvbmVudAoKYGBge3J9CnVzZ2FzIDwtIGFzLnh0cyhVU2dhcykKZ2dwbG90KGRhdGEgPSB1c2dhcywgYWVzKHggPSB5ZWFyKGluZGV4KHVzZ2FzKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1vbnRoKGluZGV4KHVzZ2FzKSwgbGFiZWwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAoMSAvIGRhdGEpKSkgKwogIGdlb21fdGlsZSgpCmBgYAoKVGhlIHBsb3QgYWJvdmUgc2hvd3MgYSBzZWFzb25hbCBjeWNsZS4KCmBgYHtyfQp1c19lbXBfcnQgPC0gYXMueHRzKFVTVW5SYXRlKQoKZ2dwbG90KGRhdGEgPSB1c19lbXBfcnQsIGFlcyh4ID0geWVhcihpbmRleCh1c19lbXBfcnQpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1vbnRoKGluZGV4KHVzX2VtcF9ydCksIGxhYmVsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IDEgLyBkYXRhKSkgKwogIGdlb21fdGlsZSgpCmBgYAoKVGhpcyBwbG90IHNob3dzIGN5Y2xlcy4KCiMjIFdoaXRlIG5vaXNlCgpBIHdoaXRlIG5vaXNlIHBhdHRlcm4gaXMgYSBsYWNrIG9mIGEgcGF0dGVybi4gVGhlcmUgYXJlIHNvbWUgbWV0aG9kcyB0byB0ZXN0IGlmIGEgc2VyaWVzIGlzIHdoaXRlIG5vaXNlLgoKLSAgIHBsb3QgaXQgb3V0IGFuIGV5ZWJhbGwKCi0gICBNZWFzdXJlIHRoZSBjb3JyZWxhdGlvbiB3aXRoIHRoZSBhdXRvY29ycmVsYXRpb24gZnVuY3Rpb24KCi0gICB0aGUgTGp1bmctQm94IHRlc3R6OyB0aGUgbnVsbCBoeXBvdGhlc2lzIGFzc3VtZXMgdGhhdCB0aGUgbGFncyBhcmUgbm90IGNvcnJlbGF0ZWQuCgojIyBUaGUgaXJyZWd1bGFyIGNvbXBvbmVudAoKVGhpcyBpcyB0aGUgcmVtYWluZGVyIGJldHdlZW4gdGhlIHNlcmllcyBhbmQgc3RydWN0dXJhbCBjb21wb25lbnRzLgoKIyBUaGUgYWRkaXRpdmUgdmVyc3VzIHRoZSBtdWx0aXBsaWNhdGl2ZSBtb2RlbAoKV2UgY2xhc3NpZnkgYSBzZXJpZXMgYXMgYWRkaXRpdmUgd2hlbmV2ZXIgdGhlcmUgaXMgZ3Jvd3RoIGluIHRoZSB0cmVuZCwgb3IgaWYgdGhlIGFtcGxpdHVkZSBvZiB0aGUgc2Vhc29uYWwgY29tcG9uZW50IHJlbWFpbnMgdGhlIHNhbWUgb3ZlciB0aW1lLgoKV2UgY2xhc3NpZnkgYSBzZXJpZXMgYXMgbXVsdGlwbGljYXRpdmUgd2hlbmV2ZXIgdGhlIGdyb3d0aCBvZiB0aGUgdHJlbmQgb3IgdGhlIG1hZ25pdHVkZSBvZiB0aGUgc2Vhc29uYWwgY29tcG9uZW50IGluY3JlYXNlcyBvciBkZWNyZWFzZXMgYnkgc29tZSBtdWx0aXBsaWNpdHkgZnJvbSBwZXJpb2QgdG8gcGVyaW9kIG92ZXIgdGltZS4KCkhlcmUgaXMgYW4gZXhhbXBsZSBvZiBhbiBhZGRpdGl2ZSBzZXJpZXM6CgpgYGB7cn0KdHNfcGxvdChVU2dhcykKYGBgCgpIZXJlIGlzIGFuIGV4YW1wbGUgb2YgYSBtdWx0aXBsaWNhdGl2ZSBzZXJpZXM6CgpgYGB7cn0KZGF0YSgiQWlyUGFzc2VuZ2VycyIpCgp0c19wbG90KEFpclBhc3NlbmdlcnMpCmBgYAoKIyMgSGFuZGxpbmcgbXVsdGlwbGljYXRpdmUgc2VyaWVzCgpNb3N0IGZvcmVjYXN0aW5nIG1vZGVscyBhc3N1bWUgdGhhdCB0aGUgdmFyaWF0aW9uIG9mIHRoZSBpbnB1dCBzZXJpZXMgcmVtYWlucyBjb25zdGFudCBvdmVyIHRpbWUuIFRoaXMgdXN1YWxseSBob2xkcyBmb3IgYSBzZXJpZXMgd2l0aCBhbiBhZGRpdGl2ZSBzdHJ1Y3R1cmUsIGJ1dCBmYWlscyB3aXRoIGEgbXVsdGlwbGljYXRpdmUgc3RydWN0dXJlLiBUaGUgY29tbW9uIHNvbHV0aW9uIGlzIHRvIGFwcGx5IGEgZGF0YSB0cmFuc2Zvcm1hdGlvbjoKCi0gICBsb2cgdHJhbnNmb3JtYXRpb246IGFwcGx5IHRoZSAkbG9nJCB0byBib3RoIHNpZGVzIG9mIHRoZSBzZXJpZXMgZXF1YXRpb24KCi0gICBib3gtY294IHRyYW5zZm9ybWF0aW9uOiBhcHBseWluZyBwb3dlciBvbiB0aGUgaW5wdXQgc2VyaWVzIHdpdGggdGhlIGJveC1jb3ggZm9ybXVsYQoKYGBge3J9CmxpYnJhcnkoZm9yZWNhc3QpCgphaXJfcGFzc2VuZ2VyX2xhbWJkYSA8LSBCb3hDb3gubGFtYmRhKEFpclBhc3NlbmdlcnMpCmFpcl9wYXNzZW5nZXJfbGFtYmRhCmBgYAoKV2UgY2FuIHVzZSB0aGUgY29lZmZpY2llbnQgdG8gdHJhbnNmb3JtIHRoZSBpbnB1dCBzZXJpZXMgd2l0aCB0aGUgYEJveENveGAgdHJhbnNmb3JtYXRpb24gYW5kIHBsb3QgaXQ6CgpgYGB7cn0KYWlyX3Bhc3Nlbmdlcl90cmFucyA8LSBCb3hDb3goQWlyUGFzc2VuZ2VycywgbGFtYmRhID0gYWlyX3Bhc3Nlbmdlcl9sYW1iZGEpCgp0c19wbG90KGFpcl9wYXNzZW5nZXJfdHJhbnMpCmBgYAoKIyBUaGUgZGVjb21wb3NpdGlvbiBvZiB0aW1lIHNlcmllcwoKT25jZSB0aGUgZGF0YSBoYXMgYmVlbiBjbGVhbmVkIGFuZCByZWZvcm1hdHRlZCwgd2UgbmVlZCB0byBpZGVudGlmeSB0aGUgc3RydWN0dXJlIG9mIHRoZSBzZXJpZXMgY29tcG9uZW50cy4gVGhlIGRlY29tcG9zaXRpb24gb2YgYSBzZXJpZXMgaXMgYSBnZW5lcmljIG5hbWUgZm9yIHRoZSBwcm9jZXNzIG9mIHNlcGFyYXRpbmcgYSBzZXJpZXMgaW50byBpdHMgY29tcG9uZW50cy4KCiMjIENsYXNzaWNhbCBzZWFzb25hbCBkZWNvbXBvc2l0aW9uCgpUaGlzIGlzIGEgdGhyZWUgc3RlcCBwcm9jZXNzOgoKMS4gIHRyZW5kIGVzdGltYXRpb246IHVzZXMgdGhlIE1BIGZ1bmN0aW9uIHRvIHJlbW92ZSB0aGUgc2Vhc29uYWwgY29tcG9uZW50IGZyb20gdGhlIHNlcmllcy4gVEhlIG9yZGVyIG9mIHRoZSBNQSBmdW5jdGlvbiBpcyBkZXRlcm1pbmVkIGJ5IHRoZSBmcmVxdWVuY3kgb2YgdGhlIHNlcmllcy4KMi4gIFNlYXNvbmFsIGNvbXBvbmVudCBlc3RpbWF0aW9uOiBUd28gc3RlcCBwcm9jZXNzIHRoYXQgc3RhcnRzIHdpdGggZGV0cmVuZGluZyB0aGUgc2VyaWVzIGJ5IHN1YnRyYWN0aW5nIHRoZSB0cmVuZCBlc3RpbWF0aW9uIGZyb20gdGhlIHByZXZpb3VzIHN0ZXAuIEFmdGVyIHRoZSBzZXJpZXMgaXMgZGV0cmVuZGVkLCB0aGUgbmV4dCBzdGVwIGlzIHRvIGVzdGltYXRlIHRoZSBzZWFzb25hbCBjb21wb25lbnQgZm9yIGVhY2ggZnJlcXVlbmN5IHVuaXQuIFRoaXMgaXMgZG9uZSBieSBncm91cGluZyB0aGUgb2JzZXJ2YXRpb25zIGJ5IHRoZWlyIGZyZXF1ZW5jeSB1bml0IGFuZCB0aGVuIGF2ZXJhZ2luZyBlYWNoIGdyb3VwLgozLiAgSXJyZWd1bGFyIGNvbXBvbmVudCBlc3RpbWF0aW9uOiBzdWJ0cmFjdGluZyB0aGUgZXN0aW1hdGlvbiBvZiB0aGUgdHJlbmQgYW5kIHNlYXNvbmFsIGNvbXBvbmVudHMgZnJvbSB0aGUgb3JpZ2luYWwgc2VyaWVzLgoKV2UgY2FuIGRvIGFsbCBvZiB0aGlzIHdpdGggdGhlIGBkZWNvbXBvc2UoKWAgZnVuY3Rpb246CgpgYGB7cn0KdXN2X2RlY29tcG9zZWQgPC0gZGVjb21wb3NlKFVTVlNhbGVzKQoKc3RyKHVzdl9kZWNvbXBvc2VkKQpgYGAKCi0gICBgeGAgaXMgdGhlIG9yaWdpbmFsIHNlcmllcwoKLSAgIGBzZWFzb25hbGAgaXMgdGhlIGVzdGltYXRlIG9mIHRoZSBzZWFzb25hbCB0cmVuZAoKLSAgIGB0cmVuZGAgaXMgdGhlIGVzdGltYXRlIG9mIHRoZSBzZXJpZXMgdHJlbmQKCi0gICBgcmFuZG9tYCBpcyB0aGUgaXJyZWd1bGFyIGNvbXBvbmVudAoKLSAgIGBmaWd1cmVgIGVzdGltYXRlZCBzZWFzb25hbCBmaWd1cmUgb25seQoKLSAgIGB0eXBlYCB0aGUgdHlwZSBvZiBkZWNvbXBvc2l0aW9uLCBlaXRoZXIgYWRkaXRpdmUgb3IgbXVsdGlwbGljYXRpdmUKCmBgYHtyfQpwbG90KHVzdl9kZWNvbXBvc2VkKQpgYGAKCkFuZCB3aXRoIGEgbXVsdGlwbGljYXRpdmUgbW9kZWw6CgpgYGB7cn0KYWlyX2RlY29tcG9zZWQgPC0gZGVjb21wb3NlKEFpclBhc3NlbmdlcnMsIHR5cGUgPSAibXVsdGlwbGljYXRpdmUiKQoKcGxvdChhaXJfZGVjb21wb3NlZCkKYGBgCgpPbmUgbGltaXRhdGlvbiBvZiB0aGUgY2xhc3NpY2FsIGRlY29tcG9zaXRpb24gbWV0aG9kIGlzIHRoYXQgdGhlIHNlYXNvbmFsIGNvbXBvbmVudCB1c2VzIHRoZSBhcml0aG1ldGljIGF2ZXJhZ2UuIFRoaXMgbWVhbnMgdGhhdCB0aGVyZSBpcyBhIHNpbmdsZSBzZWFzb25hbCBjb21wb25lbnQgZXN0aW1hdGlvbiBmb3IgZWFjaCBjeWNsZSB1bml0LiBUaGlzIGlzIGZpbmUgd2l0aCBhZGRpdGl2ZSBtb2RlbHMsIGJ1dCBjYW4gYmUgcHJvYmxlbWF0aWMgd2l0aCBtdWx0aXBsaWNhdGl2ZSBtb2RlbHMgc2luY2UgdGhlIHNlYXNvbmFsIGFzcGVjdCBjaGFuZ2VzIG92ZXIgdGltZS4KCiMgU2Vhc29uYWwgQWRqdXN0bWVudAoKU2Vhc29uYWwgYWRqdXN0bWVudCBpcyB0aGUgcHJvY2VzcyBvZiByZW1vdmluZyB0aGUgc2Vhc29uYWwgZmx1Y3R1YXRpb24gZnJvbSBhIHNlcmllcy4gVGhlIHRyYW5zZm9ybWF0aW9uIHByb2Nlc3Mgb2YgdGhlIHNlYXNvbmFsIGFkanVzdG1lbnQgbWV0aG9kIGlzIHN0cmFpZ2h0Zm9yd2FyZDoKCjEuICBFc3RpbWF0ZSB0aGUgc2Vhc29uYWwgY29tcG9uZW50IHVzaW5nIGEgZGVjb21wb3NpdGlvbiBwcm9jZXNzCjIuICBSZW1vdmUgdGhlIHNlYXNvbmFsIGNvbXBvbmVudCBmcm9tIHRoZSBzZXJpZXMsIHdoaWNoIGxlYXZlcyB0aGUgc2VyaWVzIHdpdGggb25seSB0aGUgdHJlbmQgYW5kIHRoZSBpcnJlZ3VsYXIgY29tcG9uZW50CjMuICBPcHRpb25hbGwsIHlvdSBjYW4gYXBwbHkgYSBzbW9vdGhpbmcgZnVuY3Rpb24gdG8gcmVtb3ZlIG5vaXNlIGFuZCBvdXRsaWVycwo=